/*
 * Copyright 2018-present KunMinX
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.pbase.ui.page;


import android.app.Activity;
import android.app.Application;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.util.SparseArray;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.inputmethod.InputMethodManager;

import com.blankj.utilcode.util.AdaptScreenUtils;
import com.blankj.utilcode.util.BarUtils;
import com.blankj.utilcode.util.KeyboardUtils;
import com.blankj.utilcode.util.ScreenUtils;
import com.blankj.utilcode.util.Utils;
import com.hjq.permissions.Permission;
import com.hjq.permissions.XXPermissions;
import com.hjq.toast.ToastUtils;
import com.hjq.xtoast.XToast;
import com.lxj.xpopup.XPopup;
import com.lxj.xpopup.impl.LoadingPopupView;
import com.pbase.BaseApplication;
import com.pbase.R;
import com.pbase.domain.usercase.BaseUserCase;
import com.pbase.tools.Logger;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import androidx.databinding.ViewDataBinding;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;

/**
 * 参考 https://github.com/KunMinX/Strict-DataBinding
 * Create by KunMinX at 19/8/1
 */
public abstract class BaseActivity extends AppCompatActivity {

    private ViewDataBinding mBinding;
    private ViewModelProvider mActivityProvider;
    private ViewModelProvider mApplicationProvider;
    public boolean isWindow  =false;
    private LoadingPopupView loadingPopup;

    /**
     * TODO tip: 警惕使用。非必要情况下，尽可能不在子类中拿到 binding 实例乃至获取 view 实例。使用即埋下隐患。
     * 如果这样说还不理解的话，详见 https://xiaozhuanlan.com/topic/9816742350 和 https://xiaozhuanlan
     * .com/topic/2356748910
     *
     * @return binding
     */
    protected ViewDataBinding cautiousGetBinding() {
        return mBinding;
    }

    protected abstract void onCreateBefore();

    protected abstract void onCreateAfter();

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        Logger.d(getClass(),"onCreate ");
        onCreateBefore();
        super.onCreate(savedInstanceState);
        AppManager.getInstance().addActivity(this);
        // 状态栏相关
        BarUtils.setStatusBarColor(this, Color.TRANSPARENT);//设置状态栏颜色(透明)
        BarUtils.setStatusBarLightMode(this, true);//设置状态栏是否为浅色模式

        /**
         * 网络状态广播
         * 有需要的界面单独实现该功能
         */
//        getLifecycle().addObserver(NetWorkManage.getInstance());//网络状态广播类，绑定生命周期
//        NetWorkManage.getInstance().setNetWorkConnectionListsener(this);

        initViewModel();
        DataBindingConfig dataBindingConfig = getDataBindingConfig();

        //TODO tip: DataBinding 严格模式：
        // 将 DataBinding 实例限制于 base 页面中，默认不向子类暴露，
        // 通过这样的方式，来彻底解决 视图调用的一致性问题，
        // 如此，视图调用的安全性将和基于函数式编程思想的 Jetpack Compose 持平。

        // 如果这样说还不理解的话，详见 https://xiaozhuanlan.com/topic/9816742350 和 https://xiaozhuanlan
        // .com/topic/2356748910

        ViewDataBinding binding = DataBindingUtil.setContentView(this,
                dataBindingConfig.getLayout());
        binding.setLifecycleOwner(this);
        binding.setVariable(dataBindingConfig.getVmVariableId(),
                dataBindingConfig.getStateViewModel());
        SparseArray bindingParams = dataBindingConfig.getBindingParams();
        for (int i = 0, length = bindingParams.size(); i < length; i++) {

            binding.setVariable(bindingParams.keyAt(i), bindingParams.valueAt(i));
        }
        mBinding = binding;

        //usercase 与界面生命周期绑定
        for (BaseUserCase baseUserCase : dataBindingConfig.getStateViewModel().getUserCaseList()) {
            baseUserCase.setTag(this.getClass());
            getLifecycle().addObserver(baseUserCase);
        }

        dataBindingConfig.getStateViewModel().errorTip.observe(this, s -> {
            showToast(s);
        });
        //开关 等待提示
        dataBindingConfig.getStateViewModel().isShowWaitDialog.observe(this, aBoolean -> {
            if (aBoolean) {
                showWaitDialog();
            } else {
                cancleWaitDialog();
            }
        });

        isWindow =XXPermissions.isGranted( this, Permission.SYSTEM_ALERT_WINDOW) ;
        onCreateAfter();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Logger.d(getClass(),"onDestroy ");
        AppManager.getInstance().removeActivity(this);
        mBinding.unbind();
        mBinding = null;
    }

    @Override
    protected void onResume() {
        super.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
    }

    /**
     * 只作ViewModel实例化
     */
    protected abstract void initViewModel();
    /**
     * 只作 DataBinding获取
     */
    protected abstract DataBindingConfig getDataBindingConfig();

    //TODO tip 2: Jetpack 通过 "工厂模式" 来实现 ViewModel 的作用域可控，
    //目前我们在项目中提供了 Application、Activity、Fragment 三个级别的作用域，
    //值得注意的是，通过不同作用域的 Provider 获得的 ViewModel 实例不是同一个，
    //所以如果 ViewModel 对状态信息的保留不符合预期，可以从这个角度出发去排查 是否眼前的 ViewModel 实例不是目标实例所致。
    //通过对ViewModelProvider 的封装，将【ViewModelProvider(this);】的作用域参数给控制在基类中
    //如果这样说还不理解的话，详见 https://xiaozhuanlan.com/topic/6257931840

    protected <T extends ViewModel> T getActivityScopeViewModel(@NonNull Class<T> modelClass) {
        if (mActivityProvider == null) {
            mActivityProvider = new ViewModelProvider(this);
        }
        return mActivityProvider.get(modelClass);
    }

    protected <T extends ViewModel> T getApplicationScopeViewModel(@NonNull Class<T> modelClass) {
        if (mApplicationProvider == null) {
            mApplicationProvider =
                    new ViewModelProvider((BaseApplication) this.getApplicationContext() );
        }
        return mApplicationProvider.get(modelClass);
    }


    /**
     * 应该是判断activity是不是在栈中
     */
    private Application checkApplication(Activity activity) {
        Application application = activity.getApplication();
        if (application == null) {
            //您的活动/片段尚未附加到应用程序。在onCreate调用之前不能请求ViewModel
            throw new IllegalStateException("Your activity/fragment is not yet attached to "
                    + "Application. You can't request ViewModel before onCreate call.");
        }
        return application;
    }

    /**
     * 屏幕适配相关
     */
    @Override
    public Resources getResources() {
        if (ScreenUtils.isPortrait()) {
            return AdaptScreenUtils.adaptWidth(super.getResources(), 360);
        } else {
            return AdaptScreenUtils.adaptHeight(super.getResources(), 640);
        }
    }

    /**
     * 如果输入法在窗口上已经显示，则隐藏，反之则显示
     */
    protected void toggleSoftInput() {
        InputMethodManager imm =
                (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
        imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
    }

    /**
     * 根据用户的数据类型打开相应的Activity
     */
    protected void openUrlInBrowser(String url) {
        Uri uri = Uri.parse(url);
        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
        startActivity(intent);
    }

    /**
     * 显示等待框
     */
    /**
     * 显示等待框
     */
    protected void showWaitDialog() {
        showWaitDialog(getResources().getString(R.string.please_wait),0,null);
    }
    protected void showWaitDialog(String tip) {
        showWaitDialog(tip,0,null);
    }
    /**
     * 显示等待框
     */
    protected void showWaitDialog(String tip,long time,Runnable runnable) {
        if (loadingPopup == null) {
            loadingPopup = (LoadingPopupView) new XPopup.Builder(this   )
                    .dismissOnBackPressed(false)
                    .dismissOnTouchOutside(false)
                    .isLightNavigationBar(true)
                    .asLoading(getResources().getString(R.string.please_wait))
                    .show() ;
            if (time !=0){
                if (runnable !=null){
                    loadingPopup. delayDismissWith (time ,runnable );
                }else {
                    loadingPopup. delayDismiss (time  );
                }

            }
        }else {
            loadingPopup.setTitle(tip);
            loadingPopup.show();
        }
    }


    /**
     * 取消等待框
     */
    protected void cancleWaitDialog() {
       if (loadingPopup!=null){
           loadingPopup.dismiss();
       }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        KeyboardUtils.hideSoftInput(this);
        return super.dispatchTouchEvent(ev);
    }

    public void showToast(String s ){
        showToast(s,2000);
    }
    /**
     * @param s
     * @param time 单位毫秒
     */
    public void showToast(String s,int time){
        if (isWindow ){
            new XToast<>(  Utils.getApp())
                    .setContentView(R.layout.toast_hint)
                    .setDuration(time)
                    .setAnimStyle(android.R.style.Animation_Translucent)
                    .setText(R.id.toast_tv, s)
                    .setGravity(Gravity.BOTTOM)
                    .setYOffset((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, getResources().getDisplayMetrics()))
                    .show();

        }else{
           ToastUtils.show(s);
        }

    }
}
